package io.noties.markwon.plugin.highlight.parser

import io.noties.markwon.plugin.highlight.model.Highlight
import org.commonmark.node.Node
import org.commonmark.node.Nodes
import org.commonmark.node.SourceSpans
import org.commonmark.parser.delimiter.DelimiterProcessor
import org.commonmark.parser.delimiter.DelimiterRun

/**
 * Extension for GFM Highlight using {@code =} or {@code ==} (GitHub Flavored Markdown).
 * <p>Example input:</p>
 * <pre>{@code =foo= or ==bar==}</pre>
 * <p>
 **/

class HighlightDelimiterProcessor @JvmOverloads constructor(private val requireTwoTildes: Boolean = true) :
    DelimiterProcessor {
    override fun getOpeningCharacter(): Char {
        return '='
    }

    override fun getClosingCharacter(): Char {
        return '='
    }

    override fun getMinLength(): Int {
        return if (requireTwoTildes) 2 else 1
    }

    override fun process(openingRun: DelimiterRun, closingRun: DelimiterRun): Int {
        return if (openingRun.length() == closingRun.length() && openingRun.length() <= 2) {
            // GitHub only accepts either one or two delimiters, but not a mix or more than that.
            val opener = openingRun.opener

            // Wrap nodes between delimiters in strikethrough.
            val highlight: Node = Highlight()
            val sourceSpans = SourceSpans()
            sourceSpans.addAllFrom(openingRun.getOpeners(openingRun.length()))
            for (node in Nodes.between(opener, closingRun.closer)) {
                highlight.appendChild(node)
                sourceSpans.addAll(node.sourceSpans)
            }
            sourceSpans.addAllFrom(closingRun.getClosers(closingRun.length()))
            highlight.sourceSpans = sourceSpans.sourceSpans
            opener.insertAfter(highlight)
            openingRun.length()
        } else {
            0
        }
    }
}